#[warn(dead_code)]
struct Credentials<T>
where
    T: Fn(&str, &str) -> bool,
{
    username: String,
    password: String,
    validator: T,
}

impl<T> Credentials<T>
where
    T: Fn(&str, &str) -> bool,
{
    fn is_valid(&self) -> bool {
        (self.validator)(&self.username, &self.password)
    }
}

fn main() {
    let weak_password = "password123!".to_string();
    // 闭包
    let validator = |username: &str, password: &str| !username.is_empty() && !password.is_empty();
    let validator2 = |username: &str, password: &str| {
        !username.is_empty()
            && !password.is_empty()
            && password.len() > 6
            && password.contains(['!', '@', '#', '$', '%', '^', '&', '*'])
            && password != weak_password
    };

    let creds = Credentials {
        username: "daniel".to_string(),
        // password: "password123!".to_string(),
        password: "password123!".to_string(),
        validator: validator2,
    };

    println!(
        " {} ",
        validate_credentials(&creds.username, &creds.password)
    );
    println!(" {} ", validator(&creds.username, &creds.password));
    println!(" {} ", creds.is_valid());

    let password_validator1 = get_simple_validator(6);
    println!("{}", password_validator1("123456", "123456"));

    let password_validator2 = get_password_validator(6, true);
    println!("{}", password_validator2("123456", "123456"));

    // 示例变量
    let x = 10;
    let mut y = 20;
    let z = String::from("hello");

    // Fn 示例：以不可变借用的方式捕获 x
    let fn_closure = |a| a + x;
    println!("Fn closure result: {}", fn_closure(5));
    println!("Fn closure result again: {}", fn_closure(10));

    // FnMut 示例：以可变借用的方式捕获 y
    let mut fn_mut_closure = |a| {
        y += a;
        y
    };
    println!("FnMut closure result: {}", fn_mut_closure(5));
    println!("FnMut closure result again: {}", fn_mut_closure(10));

    // FnOnce 示例：以获取所有权的方式捕获 z
    let fn_once_closure = move |a| format!("{} {}", z, a);
    println!("FnOnce closure result: {}", fn_once_closure("world"));
    // 下面这行代码会报错，因为 z 的所有权已经被转移
    // println!("{}", z);

    /*
     在 Rust 中，所有权是核心概念，每个值在任一时刻有且只有一个所有者。当把值传递给函数时，默认会发生所有权转移。若不想转移所有权，就可以使用借用（borrowing），借用通过引用（reference）实现，引用使用 & 符号表示。

     在你的代码里，&i32 和 &V 都表示引用。使用引用作为参数，函数就能在不获取值所有权的情况下访问该值。函数调用结束后，原始值的所有者依然可以正常使用这个值。
    */
    let greater_then = |x: &i32| *x > 10;
    let result = are_both_true(greater_then, less_then, &9);
    println!("{}", result);
}

fn less_then(x: &i32) -> bool {
    *x < 20
}

fn are_both_true<V>(f1: fn(&V) -> bool, f2: fn(&V) -> bool, item: &V) -> bool {
    f1(item) && f2(item)
}

fn validate_credentials(username: &str, password: &str) -> bool {
    !username.is_empty() && !password.is_empty()
}
// 假设只返回一种简单的验证逻辑
fn get_simple_validator(min_len: usize) -> impl Fn(&str, &str) -> bool {
    move |_: &str, password: &str| password.len() >= min_len
}
/*
 为什么要用Box,不用可以吗
 在 Rust 中，闭包和 trait 对象在编译时大小是不确定的，而函数参数、返回值以及局部变量的类型大小必须在编译时确定。Box 是一个智能指针，它将数据存储在堆上，自身在栈上仅保存一个指针，这样就能保证类型大小在编译时是固定的。因此，当需要返回一个动态大小的闭包或 trait 对象时，就需要使用 Box 来将其存储在堆上。
*/
// 定义类型别名简化复杂类型
type PasswordValidator = Box<dyn Fn(&str, &str) -> bool>;
fn get_password_validator(min_len: usize, special_char: bool) -> PasswordValidator {
    if special_char {
        // Box::new 用于在堆上分配内存并存储闭包 存储在堆上的动态分发的闭包或函数指针 Box 实现了 Drop trait，当 Box 离开作用域时，会自动释放堆上的内存。但如果 Box 存储的闭包持有大量数据，可能会导致内存占用过高。
        // move 关键字表明闭包会捕获环境变量的所有权 避免变量在函数返回后被释放。示例中的 min_len 和 special_char 就是通过 move 捕获的
        // _ 是一个特殊的标识符，用于表示忽略该变量
        Box::new(move |_: &str, password: &str| {
            password.len() >= min_len && password.contains(['!', '@', '#', '$', '%', '^', '&', '*'])
        })
    } else {
        Box::new(move |_: &str, password: &str| password.len() >= min_len)
    }
}
